//----------------------------------------------------------------------------
// command.cpp
//
// base for swine commands and command map
//
// Copyright (C) 2011 Neil Butterworth
//----------------------------------------------------------------------------

#include "command.h"
#include "error.h"
#include <cstdio>

using std::string;

namespace Swine {

//----------------------------------------------------------------------------
// Currently executing dialog command
//----------------------------------------------------------------------------

const Command * Command :: mDialogCommand = 0;

void Command :: SetDialogCommand( const Command * cmd ) {
	mDialogCommand = cmd;
}

//----------------------------------------------------------------------------
// Create command from command name and short help text
//----------------------------------------------------------------------------

Command :: Command( const string & name, const string & help )
					: mName( name ), mHelp( help ) {
}

//----------------------------------------------------------------------------
// Do-nothing virtual dtor
//----------------------------------------------------------------------------

Command :: ~Command() {
}

//----------------------------------------------------------------------------
// Get name & help
//----------------------------------------------------------------------------

string Command :: Name() const {
	return mName;
}

string Command :: Help() const {
	return mHelp;
}

//----------------------------------------------------------------------------
// Default handler for WM_COMMAND messages does nothing
//----------------------------------------------------------------------------

BOOL Command :: ProcessControlMessages( HWND , int , int  ) const {
	return TRUE;
}

//----------------------------------------------------------------------------
// Basic dialog box procedure
//----------------------------------------------------------------------------

BOOL CALLBACK DialogProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM  ) {

    switch (message)    {
		case WM_COMMAND:
			return Command::DialogCommand()->ProcessControlMessages(
						hwnd, LOWORD(wParam), HIWORD (wParam) );

		case WM_INITDIALOG:
			return TRUE;

		case WM_DESTROY:
			PostQuitMessage(0);
			return TRUE;

		case WM_CLOSE:
			DestroyWindow (hwnd);
			return TRUE;
	}

    return FALSE;
}

//----------------------------------------------------------------------------
// Static to get the command that is being executed to display  adialog
//----------------------------------------------------------------------------

const Command * Command :: DialogCommand() {
	if ( ! mDialogCommand ) {
		throw Error( "DialogCommand not initialised" );
	}
	return mDialogCommand;
}

//----------------------------------------------------------------------------
// Default dialog initialisation does nothing
//----------------------------------------------------------------------------

void Command :: InitDialog( HWND, CmdLine & ) const {
}

//----------------------------------------------------------------------------
// Display dialog box
//----------------------------------------------------------------------------

int Command :: DoDialog( int dres, CmdLine & cl ) const {

	SetDialogCommand( this );
	HWND dlg = CreateDialog(  GetModuleHandle(0),
								MAKEINTRESOURCE( dres ), 0, & DialogProc );
	InitDialog( dlg, cl );

	MSG  msg;

    while ( GetMessage( & msg, 0, 0, 0 ) ) {
        if ( ! IsDialogMessage( dlg, & msg ) ) {
            TranslateMessage( & msg );
            DispatchMessage( & msg );
        }
    }
	return 0;
}
//----------------------------------------------------------------------------
// Currently do nothing
//----------------------------------------------------------------------------

CommandDict :: CommandDict() {
}

CommandDict :: ~CommandDict() {
}

//----------------------------------------------------------------------------
// Get singleton dictionary instance
//----------------------------------------------------------------------------

CommandDict & CommandDict :: Instance() {
	static CommandDict instance;
	return instance;
}

//----------------------------------------------------------------------------
// Add command to dictionary
//----------------------------------------------------------------------------

void CommandDict :: Add( const Command * cmd ) {
	if ( mDict.find( cmd->Name() ) != mDict.end() ) {
		throw Error( "Duplicate command name: " + cmd->Name() );
	}
	else {
		mDict.insert( std::make_pair( cmd->Name(), cmd ) );
	}
}

//----------------------------------------------------------------------------
// Look up command, returning NULL if it does not exist.
//----------------------------------------------------------------------------

const Command * CommandDict :: Find( const std::string &  name ) const {

	DictType::const_iterator it = mDict.find( name );
	if ( it == mDict.end() ) {
		return 0;
	}
	else {
		return it->second;
	}
}

//----------------------------------------------------------------------------
// Get the full help string
//----------------------------------------------------------------------------

string CommandDict :: GetLongHelp( const string & name  ) const {
	const Command * c = Find( name );
	if ( c == 0 ) {
		throw Error( "Unknown command: " + name );
	}
	return c->Help();
}


//----------------------------------------------------------------------------
// write out help texts using dictionary
//----------------------------------------------------------------------------

void CommandDict :: WriteHelp() const {
	for ( DictType::const_iterator it = mDict.begin();
				it != mDict.end(); ++it ) {
		//os << it->second->Name().c_str() << "\t - " << it->second->Help().c_str() << "\n";
		string help = it->second->Help();
		string::size_type nlpos = help.find_first_of( "\n" );
		if ( nlpos != string::npos ) {
			help = help.substr( 0, nlpos );
		}

		printf( "%-10.10s - %s\n", it->second->Name().c_str(), help.c_str() );
	}

}

//----------------------------------------------------------------------------

} // namespace

